package example

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
	"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
	"github.com/flipped-aurora/gin-vue-admin/server/model/example"
	exampleRes "github.com/flipped-aurora/gin-vue-admin/server/model/example/response"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
)

type FileUploadAndDownloadApi struct{}

// UploadFile
// @Tags      ExaFileUploadAndDownload
// @Summary   上传文件示例
// @Security  ApiKeyAuth
// @accept    multipart/form-data
// @Produce   application/json
// @Param     file  formData  file                                                           true  "上传文件示例"
// @Success   200   {object}  response.Response{data=exampleRes.ExaFileResponse,msg=string}  "上传文件示例,返回包括文件详情"
// @Router    /fileUploadAndDownload/upload [post]
func (b *FileUploadAndDownloadApi) UploadFile(c *gin.Context) {
	permission, err := strconv.ParseBool(c.PostForm("permission"))
	if err != nil {
		response.FailWithMessage("入参解析失败", c)
		return
	}
	param := example.ExaUploadFile{
		NoSave:     c.PostForm("noSave"),
		UserName:   c.PostForm("userName"),
		Permission: permission,
		Dir:        c.PostForm("dir"),
	}
	log.Printf("UploadFile 入参:%v\n", param)
	// 检查入参
	if param.UserName == "" || param.Dir == "" {
		response.FailWithMessage("入参校验失败", c)
		return
	}
	if param.NoSave == "" {
		param.NoSave = "0"
	}
	_, header, err := c.Request.FormFile("file")
	if err != nil {
		global.GVA_LOG.Error("接收文件失败!", zap.Error(err))
		response.FailWithMessage("接收文件失败", c)
		return
	}
	var file example.ExaFileUploadAndDownload
	file, err = fileUploadAndDownloadService.UploadFile(header, param, nil) // 文件上传后拿到文件路径
	if err != nil {
		global.GVA_LOG.Error("修改数据库链接失败!", zap.Error(err))
		response.FailWithMessage("修改数据库链接失败", c)
		return
	}
	response.OkWithDetailed(exampleRes.ExaFileResponse{File: file}, "上传成功", c)
}

// UploadChunk
// @Tags      ExaFileUploadAndDownload
// @Summary   上传文件示例
// @Router    /fileUploadAndDownload/uploadChunk [post]
func (b *FileUploadAndDownloadApi) UploadChunk(c *gin.Context) {
	// 设置入参
	permission, err := strconv.ParseBool(c.PostForm("permission"))
	if err != nil {
		response.FailWithMessage("入参解析失败 permission", c)
		return
	}
	param := example.ExaUploadFile{
		NoSave:     c.PostForm("noSave"),
		UserName:   c.PostForm("userName"),
		Permission: permission,
		Dir:        c.PostForm("dir"),
		FileSize:   c.PostForm("fileSize"),
	}
	file, _ := c.FormFile("file")

	chunkNumber, _ := strconv.Atoi(c.PostForm("chunk"))
	totalChunks, _ := strconv.Atoi(c.PostForm("chunks"))
	tempDir := filepath.Join("temp", file.Filename)
	err = os.MkdirAll(tempDir, os.ModePerm)
	if err != nil {
		response.FailWithMessage("创建临时文件夹出错", c)
		return
	}
	// 保存分片
	chunkPath := filepath.Join(tempDir, fmt.Sprintf("chunk_%d", chunkNumber))
	if err := c.SaveUploadedFile(file, chunkPath); err != nil {
		response.FailWithMessage("保存分片出错", c)
		return
	}
	fmt.Println("chunkNumber:" + strconv.Itoa(chunkNumber))
	fmt.Println("totalChunks:" + strconv.Itoa(totalChunks))
	// 检查是否所有分片都已上传
	if chunkNumber == totalChunks-1 || totalChunks == 0 {
		// 合并分片
		tempDir := filepath.Join("temp", file.Filename)
		fmt.Println("tempDir:" + tempDir)
		var buffer bytes.Buffer
		for i := 0; i < totalChunks; i++ {
			chunkPath := filepath.Join(tempDir, fmt.Sprintf("chunk_%d", i))
			chunkFile, err := os.Open(chunkPath)
			if err != nil {
				response.FailWithMessage("合并分片出错 - 获取文件", c)
				return
			}
			_, err = io.Copy(&buffer, chunkFile)
			chunkFile.Close()
			if err != nil {
				response.FailWithMessage("合并分片出错 - 放入内存", c)
				return
			}
		}
		// 创建临时文件
		tempFile, err := os.CreateTemp("", "upload-*")
		if err != nil {
			response.FailWithMessage("创建临时文件失败", c)
			return
		}
		tempFileName := tempFile.Name()
		defer os.Remove(tempFileName) // 确保临时文件被删除

		// 将 buffer 的内容写入到临时文件中
		_, err = io.Copy(tempFile, &buffer)
		if err != nil {
			tempFile.Close()
			response.FailWithMessage("写入临时文件失败", c)
			return
		}
		tempFile.Close()

		header := &multipart.FileHeader{
			Filename: file.Filename,
			Size:     int64(buffer.Len()),
		}

		// 创建一个新的 multipart.File
		f, err := os.Open(tempFileName)
		if err != nil {
			response.FailWithMessage("打开临时文件失败", c)
			return
		}
		defer f.Close()

		if param.NoSave == "" {
			param.NoSave = "0"
		}
		fmt.Println("走到这里来了！")
		var file example.ExaFileUploadAndDownload
		file, err = fileUploadAndDownloadService.UploadFile(header, param, f) // 文件上传后拿到文件路径
		if err != nil {
			global.GVA_LOG.Error("修改数据库链接失败!", zap.Error(err))
			response.FailWithMessage("修改数据库链接失败", c)
			return
		}
		// 清理临时文件
		err = os.RemoveAll(tempDir)
		if err != nil {
			return
		}
		response.OkWithDetailed(exampleRes.ExaFileResponse{File: file}, "上传成功", c)
	}
}

// BatchUpload
// @Tags      ExaFileUploadAndDownload
// @Summary   批量上传文件
// @Router    /fileUploadAndDownload/batchUpload [post]
func (b *FileUploadAndDownloadApi) BatchUpload(c *gin.Context) {
	permission, err := strconv.ParseBool(c.PostForm("permission"))
	if err != nil {
		response.FailWithMessage("入参解析失败 permission", c)
		return
	}
	param := example.ExaUploadFile{
		NoSave:     c.PostForm("noSave"),
		UserName:   c.PostForm("userName"),
		Permission: permission,
		Dir:        c.PostForm("dir"),
	}
	count, err := strconv.Atoi(c.PostForm("count"))
	if err != nil {
		response.FailWithMessage("入参校验失败 count", c)
		return
	}
	log.Printf("UploadFile 入参:%v\n", param)
	// 检查入参
	if param.UserName == "" || param.Dir == "" {
		response.FailWithMessage("入参校验失败 UserName Dir", c)
		return
	}
	if param.NoSave == "" {
		param.NoSave = "0"
	}
	for i := 0; i < count; i++ {
		_, header, err := c.Request.FormFile("file" + strconv.Itoa(i))
		if err != nil {
			break
		}
		fmt.Println(header.Filename)
		_, err = fileUploadAndDownloadService.UploadFile(header, param, nil) // 文件上传后拿到文件路径
		if err != nil {
			break
		}
	}
	response.OkWithDetailed(exampleRes.ExaFileResponse{}, "上传成功", c)
}

// EditFileName 编辑文件名
func (b *FileUploadAndDownloadApi) EditFileName(c *gin.Context) {
	var file example.ExaFileUploadAndDownload
	err := c.ShouldBindJSON(&file)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = fileUploadAndDownloadService.EditFileName(file)
	if err != nil {
		global.GVA_LOG.Error("编辑失败!", zap.Error(err))
		response.FailWithMessage("编辑失败", c)
		return
	}
	response.OkWithMessage("编辑成功", c)
}

// EditFileDesc 编辑备注
func (b *FileUploadAndDownloadApi) EditFileDesc(c *gin.Context) {
	var file example.ExaFileUploadAndDownload
	err := c.ShouldBindJSON(&file)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = fileUploadAndDownloadService.EditFileDesc(file)
	if err != nil {
		global.GVA_LOG.Error("编辑失败!", zap.Error(err))
		response.FailWithMessage("编辑失败", c)
		return
	}
	response.OkWithMessage("编辑成功", c)
}

// DeleteFile
// @Tags      ExaFileUploadAndDownload
// @Summary   删除文件
// @Security  ApiKeyAuth
// @Produce   application/json
// @Param     data  body      example.ExaFileUploadAndDownload  true  "传入文件里面id即可"
// @Success   200   {object}  response.Response{msg=string}     "删除文件"
// @Router    /fileUploadAndDownload/deleteFile [post]
func (b *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) {
	var file example.ExaFileUploadAndDownload
	err := c.ShouldBindJSON(&file)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	userName := c.GetHeader("userName")
	log.Printf("DeleteFile 入参:%#v\n,userName:%v", file, userName)
	if file.Tag == "dir" {
		err = fileUploadAndDownloadService.DeleteDir(file, userName)
		if err != nil {
			response.FailWithMessage(err.Error(), c)
			return
		}
	} else {
		err = fileUploadAndDownloadService.DeleteFile(file)
	}
	if err != nil {
		global.GVA_LOG.Error("删除失败!", zap.Error(err))
		response.FailWithMessage("删除失败", c)
		return
	}
	response.OkWithMessage("删除成功", c)
}

// GetFileList
// @Tags      ExaFileUploadAndDownload
// @Summary   分页文件列表
// @Security  ApiKeyAuth
// @accept    application/json
// @Produce   application/json
// @Param     data  body      request.PageInfo                                        true  "页码, 每页大小"
// @Success   200   {object}  response.Response{data=response.PageResult,msg=string}  "分页文件列表,返回包括列表,总数,页码,每页数量"
// @Router    /fileUploadAndDownload/getFileList [post]
func (b *FileUploadAndDownloadApi) GetFileList(c *gin.Context) {
	var pageInfo request.PageInfo

	err := c.ShouldBindJSON(&pageInfo)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	log.Printf("GetFileRecordInfoList 入参:%#v\n", pageInfo)
	var list interface{}
	var total int64
	if pageInfo.UrlPath == "Dir" {
		list, total, err = fileUploadAndDownloadService.GetDirRecordInfoList(pageInfo)
	} else if pageInfo.UrlPath == "File" {
		list, total, err = fileUploadAndDownloadService.GetFileRecordInfoList(pageInfo)
	} else if pageInfo.UrlPath == "Backup" {
		list, total, err = fileUploadAndDownloadService.GetBackUpRecordInfoList(pageInfo)
	}

	if err != nil {
		global.GVA_LOG.Error("获取失败!", zap.Error(err))
		response.FailWithMessage("获取失败", c)
		return
	}
	response.OkWithDetailed(response.PageResult{
		List:     list,
		Total:    total,
		Page:     pageInfo.Page,
		PageSize: pageInfo.PageSize,
	}, "获取成功", c)
}

// GetImg
// @Tags      ExaFileUploadAndDownload
// @Summary   获取指定路径的图片
func (b *FileUploadAndDownloadApi) GetImg(c *gin.Context) {
	filename := c.Query("url")
	log.Printf("入参:%s\n", filename)
	// 此处需要区分生产开发环境1
	//imagePath := filepath.Join("E:/2024demo/sample_data/server", filename)
	imagePath := filepath.Join("D:\\GOProj\\sample_data\\server", filename)
	//imagePath := filepath.Join("/home/sampledata20241008/server", filename)
	data, err := ioutil.ReadFile(imagePath)
	if err != nil {
		if os.IsNotExist(err) {
			c.JSON(http.StatusNotFound, gin.H{"error": "Image not found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read file"})
		}
		return
	}
	// 将图片数据编码为 Base64
	base64Data := base64.StdEncoding.EncodeToString(data)
	response.OkWithDetailed(base64Data, "获取成功", c)
}

// GetZipFile
// @Tags      ExaFileUploadAndDownload
// @Summary   获取指定路径的文件
func (b *FileUploadAndDownloadApi) GetZipFile(c *gin.Context) {
	var data struct {
		URL      string `json:"url"`
		FileName string `json:"fileName"`
	}
	if err := c.ShouldBindJSON(&data); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	log.Printf("入参: URL=%s, FileName=%s\n", data.URL, data.FileName)

	if data.URL != "" {
		target := filepath.Join("D:/GOProj/sample_data/server", data.URL)
		c.Header("Content-Description", "File Transfer")
		c.Header("Content-Transfer-Encoding", "binary")
		c.Header("Content-Disposition", "attachment; filename="+data.FileName)
		c.Header("Content-Type", "application/octet-stream")
		// 如果文件大小未知或动态生成，使用分块传输编码
		c.Writer.Header().Del("Content-Length") // 删除Content-Length
		c.Writer.WriteHeader(http.StatusOK)     // 必须先写入状态码
		c.File(target)
	} else {
		c.Status(http.StatusNotFound)
	}
}

// ChangePermission
// @Tags      ExaFileUploadAndDownload
// @Summary   更改权限
func (b *FileUploadAndDownloadApi) ChangePermission(c *gin.Context) {
	var file example.ExaFileUploadAndDownload
	err := c.ShouldBindJSON(&file)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = fileUploadAndDownloadService.ChangePermission(file)
	if err != nil {
		global.GVA_LOG.Error("编辑失败!", zap.Error(err))
		response.FailWithMessage("编辑失败", c)
		return
	}
	response.OkWithMessage("编辑成功", c)
}

// NewFolder
// @Tags      ExaFileUploadAndDownload
// @Summary   新建文件夹
func (b *FileUploadAndDownloadApi) NewFolder(c *gin.Context) {
	var folder example.ExaNewFolder
	err := c.ShouldBindJSON(&folder)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	log.Printf("NewFolder 入参：%#v\n", folder)

	var total int64
	db := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{})
	db = db.Where("tag = 'dir'").Where("name = ?", folder.Name).Where("logic_address = ?", folder.DirName)
	err = db.Count(&total).Error
	log.Printf("total：%#v\n", total)
	if total > 0 {
		log.Printf("已有文件夹 total:%v", total)
		response.FailWithMessage("已有文件夹", c)
		return
	}

	err = fileUploadAndDownloadService.NewFolder(folder)
	if err != nil {
		global.GVA_LOG.Error("新建文件夹失败!", zap.Error(err))
		response.FailWithMessage("新建文件夹失败", c)
		return
	}
	response.OkWithMessage("新建文件夹成功", c)
}

// GetDirList
// @Tags      ExaFileUploadAndDownload
// @Summary   获取文件夹
func (b *FileUploadAndDownloadApi) GetDirList(c *gin.Context) {
	var param example.ExaGetDirList
	err := c.ShouldBindJSON(&param)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	log.Printf("GetDirList 入参: %#v: \n", param)
	list, err := fileUploadAndDownloadService.GetDirList(param)
	if err != nil {
		global.GVA_LOG.Error("获取失败!", zap.Error(err))
		response.FailWithMessage("获取失败", c)
		return
	}
	response.OkWithDetailed(list, "获取成功", c)
}

// GetAllFileByDir
// @Tags      ExaFileUploadAndDownload
// @Summary   获取文件夹下的所有文件
func (b *FileUploadAndDownloadApi) GetAllFileByDir(c *gin.Context) {
	dir := c.Query("dir")
	userName := c.Query("userName")
	log.Printf("getAllFileByDir 入参dir: %#v: userName: %#v \n", dir, userName)
	list, err := fileUploadAndDownloadService.GetAllFileByDir(dir, userName)
	if err != nil {
		global.GVA_LOG.Error("获取失败!", zap.Error(err))
		response.FailWithMessage("获取失败", c)
		return
	}
	response.OkWithDetailed(list, "获取成功", c)
}

// GetBackupFileCount
// @Tags      ExaFileUploadAndDownload
// @Summary   获取备份文件数量
func (b *FileUploadAndDownloadApi) GetBackupFileCount(c *gin.Context) {
	name := c.Query("name")
	log.Printf("GetBackupFileCount 入参: name: %#v \n", name)
	count, err := fileUploadAndDownloadService.GetBackupFileCount(name)
	if err != nil {
		global.GVA_LOG.Error("获取失败!", zap.Error(err))
		response.FailWithMessage("获取失败", c)
		return
	}
	response.OkWithDetailed(count, "获取成功", c)
}
